package org.egame.net
{
	import com.adobe.serialization.json.JSON;
	
	import flash.events.*;
	import flash.net.Socket;
	import flash.utils.ByteArray;
	
	public class NetClient extends EventDispatcher
	{

		private var _socket : Socket;
		private var _byteBuffer : ByteArray;//recv buffer
		private var _byteLen:int = 0;//缓存中字节长度
		
		private var _svrIp : String;//ip
		private var _svrPort : int;//port

		public function NetClient()
		{
			_socket = new Socket();
			_byteBuffer = new ByteArray();

			_socket.addEventListener(Event.CONNECT, handleSocketConnection);
			_socket.addEventListener(Event.CLOSE, handleSocketDisconnection);
			_socket.addEventListener(ProgressEvent.SOCKET_DATA, handleSocketData);
			_socket.addEventListener(IOErrorEvent.IO_ERROR, handleIOError);
			_socket.addEventListener(IOErrorEvent.NETWORK_ERROR, handleIOError);
			_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, handleSecurityError);
		}

		/**
		 * connect server
		 */
		public function connect(strIp:String, iPort:int):void
		{
			_socket.connect(strIp, iPort);
			this._svrIp=strIp;
			this._svrPort=iPort;
		}


	    // -------------------------------------------------------
		// Internal Socket Event Handlers
		// -------------------------------------------------------
		private function handleSocketConnection(e:Event):void
		{
			var evtConnect:NetClientEvent = new NetClientEvent(NetClientEvent.TYPE_CONNECTED, null);	
	 		dispatchEvent(evtConnect);
		}
		
		private function handleSocketDisconnection(evt:Event):void
		{	
			// Fire event
			_socket.close();

	 		var evtDisconnect:NetClientEvent = new NetClientEvent(NetClientEvent.TYPE_CONNECT_LOST, null);	
	 		dispatchEvent(evtDisconnect);
		}
		
		private function handleIOError(evt:IOErrorEvent):void
		{
			_socket.close();
			var evtIoErr:NetClientEvent = new NetClientEvent(NetClientEvent.TYPE_IO_ERROR, null);	
		 	dispatchEvent(evtIoErr);
		}
		
		private function handleSecurityError(evt:SecurityErrorEvent):void
		{
			_socket.close();
			var evtSecurityErr:NetClientEvent = new NetClientEvent(NetClientEvent.TYPE_SECURITY_ERROR,null);
			dispatchEvent(evtSecurityErr);
		}
		
		private function handleSocketData(evt:Event):void
		{	
			//先将数据拷出来		
			var bytes:int = _socket.bytesAvailable;
		    _socket.readBytes(_byteBuffer, _byteLen, bytes);
		    _byteLen += bytes;
		    //拆包
		    var index:int = 0;
		    var header:ByteArray = new ByteArray();//包头
		    for(var i:int=0; i < _byteLen; i++)
		    {
		    	//判断包头是否收全
		    	if ((index+5)>_byteLen)
		    		break;
		    	_byteBuffer.position = index;
		    	_byteBuffer.readBytes(header, 0, 5);
		    	header.position = 1;
		    	var bodyLen:int = header.readInt();
		    	var totalLen:int = bodyLen+5;
		    	
		    	//判断包是否收全
		    	if ((index+totalLen)>_byteLen)
		    		break;
		    		
		    	//取出字节段
		    	var seg:ByteArray = new ByteArray();
		    	_byteBuffer.position = index;
		    	_byteBuffer.readBytes(seg, 0, totalLen);
		    	dealBytesSegment(seg);
		    	
		    	index += totalLen;
		    }
		    
		    var tmp :ByteArray = new ByteArray();
		    _byteBuffer.position=index;
		    _byteBuffer.readBytes(tmp, 0, _byteLen-index);
		    _byteLen -= index;
		    _byteBuffer = tmp;

		}
		
		//处理字节段
		public	function	dealBytesSegment(seg:ByteArray):void
		{
			seg.position = 0;
			var prefix:int = seg.readByte();
			var body:ByteArray = new ByteArray();
			seg.position = 5;
			seg.readBytes(body, 0, 0);
			body = preDecodeBody(prefix, body)
			var obj:Object = JSON.decode(body.toString());
			var pack:JSONPackage = new JSONPackage(0);
			pack.setInnerObj(obj);
			if(true==dealNetPackage(pack))
			{
				var	evtRecvData:NetClientEvent = new NetClientEvent(NetClientEvent.TYPE_RECV_PACKAGE, pack);
				dispatchEvent(evtRecvData);
			}
		}
		

		/**
		 * 发送JSONPackage网络包
		 */
		public function sendJSON(pack:JSONPackage):void
		{
			var obj:Object = pack.getInnerObj();
		 	var prefix:int = 0;
			if (obj.byte_prefix != undefined)
				prefix = obj.byte_prefix;
				
			var msg:String = JSON.encode(obj);
			sendString(prefix, msg);
		}
		
		 
		//预处理字节段的body，会做解压或解密操作；prefix为0，说明body是原始数据，1，压缩过的数据，2，加密过的数据
		private	function	preDecodeBody(prefix:int, body:ByteArray):ByteArray
		{
			if (prefix == 1)
			{
				body.uncompress();
			}
			if (prefix == 2)
			{
				body = decrypt(138, body);
			}
			return body;
		}
		
		//预处理数据 ,会对body压缩或加密并返回处理后的字节数组；prefix, body含义同上
		private function preEncodeBody(prefix:int, body:ByteArray):ByteArray
		{
			if (prefix==1)
			{
				body.compress();
			}
			if (prefix == 2)
			{
				body = encrypt(138, body);
			}
			return body;
		} 
		
		//简单加密
		private	function	encrypt(key:int, body:ByteArray):ByteArray
		{
			var oddKey:int  = key;
			var evenKey:int = key&0xbc;
			var evenFlag:int = 0x01;
			for(var i:int = 0; i < body.length; i++)
			{
				body.position = i;
				var b:int = body.readByte();
				body.position = i;
				if (evenFlag==0x01)
				{
					body.writeByte(b ^ evenKey);
				}
				else
				{
					body.writeByte(b ^ oddKey);
				}
				evenFlag = evenFlag ^ 0x01;
			}
			return body;
		}
		
		//解密
		private	function	decrypt(key:int, body:ByteArray):ByteArray
		{
			var oddKey:int  = key;
			var evenKey:int = key&0xbc;
			var evenFlag:int = 0x01;
			for(var i:int = 0; i < body.length; i++)
			{
				body.position = i;
				var b:int = body.readByte();
				body.position = i;
				if (evenFlag==0x01)
				{
					body.writeByte(b ^ evenKey);
				}
				else
				{
					body.writeByte(b ^ oddKey);
				}
				evenFlag = evenFlag ^ 0x01;
			}
			return body;
		}
		
		private function sendString(prefix:int, msg:String):void
		{
			var body:ByteArray = new ByteArray();
			body.writeMultiByte(msg, "utf-8");
			body = preEncodeBody(prefix, body);
			
			var total:ByteArray = new ByteArray();
			total.writeByte(prefix);//prefix
			total.writeInt(body.length);//body length
			total.writeBytes(body, 0, body.length);//write body
			_socket.writeBytes(total);
			_socket.flush();
		}
		
		//if return false ,the package is not need father process
		private function	dealNetPackage(pack:JSONPackage):Boolean
		{
			var type:int = pack.getType();
			if(type < 1)
			{
				var count:int = pack.getInt("count");
				for(var i:int = 0; i < count; i++){
					var msg:String = pack.getString("msg"+i);
					var obj:Object = JSON.decode(msg);
					var jsonPack:JSONPackage = new JSONPackage(0);
					jsonPack.setInnerObj(obj);
					var	evtRecvData:NetClientEvent = new NetClientEvent(NetClientEvent.TYPE_RECV_PACKAGE, jsonPack);
					dispatchEvent(evtRecvData);
				}
				return false;
			}
			return true;
		}
		
	}
}